package com.sneakxy.mybatis.commons.repository.config;

import java.util.Map;

import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.ibatis.binding.BindingException;
import org.apache.ibatis.binding.MapperProxyFactory;
import org.apache.ibatis.binding.MapperRegistry;
import org.apache.ibatis.binding.MybatisCommonsMapperProxyFactory;
import org.apache.ibatis.builder.annotation.MapperAnnotationBuilder;

/**
 * @author 潜行的青衣
 */
public class MybatisCommonsMapperRegistry extends MapperRegistry {

	/**
	 * @param config
	 */
	public MybatisCommonsMapperRegistry(MybatisCommonsConfiguration config) {
		super(config);
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> void addMapper(Class<T> type) {
		if (type.isInterface()) {
			if (hasMapper(type)) {
				throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
			}
			boolean loadCompleted = false;
			Map<Class<?>, MapperProxyFactory<?>> knownMappers = null;
			MybatisCommonsConfiguration config = null;
			try {
				knownMappers = (Map<Class<?>, MapperProxyFactory<?>>) FieldUtils.readField(this, "knownMappers", true);
				config = (MybatisCommonsConfiguration) FieldUtils.readField(this, "config", true);
				knownMappers.put(type, new MybatisCommonsMapperProxyFactory<T>(type));
				// It's important that the type is added before the parser is
				// run
				// otherwise the binding may automatically be attempted by the
				// mapper parser. If the type is already known, it won't try.
				MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
				parser.parse();
				loadCompleted = true;
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} finally {
				if (!loadCompleted) {
					knownMappers.remove(type);
				}
			}
		}
	}

}
